/*com os numeros passados por parametro criar uma lista duplamente encadeada que contenha todos os
  numeros do intervalo(inclusive) entre os parametros

  entrada normal
	criar lista duplamente encadeada e printar no arquivo .txt a partir do começo da lista
  entrada invertida
	criar lista duplamente encadeada e printar no arquivo .txt a partir do final da lista ate o comeco
  entrada aleatoria
	criar lista duplamente encadeada e sortear um numero. Printar esse numero no arquivo.txt remove-lo
	da lista e diminuir o contador totalNos para que o sorteio possa ser feito com o total de exato
	de numeros
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

typedef struct no{
	int numero;
	struct no *proximo;
	struct no *anterior;
}No;

typedef struct lista{
	int totalNos;
	No *inicio;
	No *fim;
}Lista;

Lista *inicializaG(){
	Lista *l=(Lista*)malloc(sizeof(Lista));

	l->totalNos = 0;
	l->inicio = NULL;
	l->fim = NULL;

	return l;
}

void insereG(Lista *l, int numero){

	No *novo=(No*)malloc(sizeof(No));

	novo->numero = numero;
	novo->anterior = NULL;
	novo->proximo = NULL;

	if(l->inicio == NULL){
		l->totalNos++;
		l->inicio= novo;
		l->fim= novo;
	}
	else{
		l->totalNos++;
		novo->anterior = l->fim;
		l->fim->proximo = novo;
		l->fim = novo;
	}
}

void criaArquivoOrdemNormal(int numeroInicial, int numeroFinal, char nomeArquivo[]){
	FILE *fp;
	int x = 0, resultado = 0;

	fp = fopen (nomeArquivo, "w");

	if (fp == NULL) {
		printf ("Houve um erro ao abrir o arquivo.\n");
		return ;
	}

	for (x = numeroInicial; x <= numeroFinal; ++x) {
		/* A funcao 'fprintf' devolve o número de bytes gravados ou EOF se houve erro na gravação */
		resultado = fprintf(fp,"%i ",x);
		if (resultado == EOF)
			printf("Erro na Gravacao\n");
	}
	fclose (fp);
}

void criaArquivoOrdemInvertida(int numeroInicial, int numeroFinal, char nomeArquivo[]){

	FILE *fp;
	int x = 0, resultado = 0;

	fp = fopen (nomeArquivo, "w");

	if (fp == NULL) {
		printf ("Houve um erro ao abrir o arquivo.\n");
		return;
	}

	for (x = numeroFinal; x >= numeroInicial; --x) {
		/* A funcao 'fprintf' devolve o número de bytes gravados ou EOF se houve erro na gravação */
		resultado = fprintf(fp,"%i ",x);
		if (resultado == EOF)
			printf("Erro na Gravacao\n");
	}
	fclose (fp);

}

int sorteiaNumeroAleatorio(int totalNumeros){ /*Função responsável por sortear um numero*/
    int numeroSorteado = 0;
    srand(time(NULL));
	numeroSorteado = rand()% totalNumeros;
	numeroSorteado++;

    return numeroSorteado;
}

int removeNo(Lista *lista, int pos){
	int i, resposta = 0;
	No *remov_elemento,*em_curso;

	if(lista->totalNos == 0)
		return -1;

	if(pos == 1){ /* remoção do 1° elemento */
		remov_elemento = lista->inicio;
		resposta = lista->inicio->numero;
		lista->inicio = lista->inicio->proximo;
		if(lista->inicio == NULL)
			lista->fim = NULL;
		else
			lista->inicio->anterior = NULL;
	}else if(pos == lista->totalNos){ /* remoção do último elemento */
		remov_elemento = lista->fim;
		resposta = lista->fim->numero;
		lista->fim->anterior->proximo = NULL;
		lista->fim = lista->fim->anterior;
	}else { /* remoção em outro lugar */
		em_curso = lista->inicio;
		for(i=1;i<pos;++i)
			em_curso = em_curso->proximo;
		remov_elemento = em_curso;
		resposta = em_curso->numero;
		em_curso->anterior->proximo = em_curso->proximo;
		em_curso->proximo->anterior = em_curso->anterior;
	}

	free(remov_elemento);
	lista->totalNos--;
	return resposta;
}

void criaArquivoOrdemAleatoria(int numeroInicial, int numeroFinal, char nomeArquivo[]){
	Lista *lista = inicializaG();
	FILE *fp;
	int x = 0, resultado = 0, numeroSorteado = 0, numeroEncontrado;

	fp = fopen (nomeArquivo, "w");
	if (fp == NULL) {
		printf ("Houve um erro ao abrir o arquivo.\n");
		return ;
	}

	for (x = numeroInicial; x <= numeroFinal; ++x) {
		insereG(lista, x);
	}
	while(lista->totalNos != 0){
		numeroSorteado = sorteiaNumeroAleatorio(lista->totalNos);
		numeroEncontrado = removeNo(lista, numeroSorteado);

		resultado = fprintf(fp,"%i ",numeroEncontrado);
		if (resultado == EOF){
			printf("Erro na Gravacao\n");
			return;
		}
	}
	fclose (fp);
}

/*int main(int argc,char *argv[]){

	int opcao = 0;

	int numeroInicial = atoi(argv[1])	;
	int numeroFinal = atoi(argv[2]);
	char tipoOrdem[10];

	strcpy(tipoOrdem, argv[3]);

	if ( !strcmp(tipoOrdem, "norm") ) {
		opcao = 1;
	} else {
		if ( !strcmp(tipoOrdem, "inver") ) {
			opcao = 2;
		} else {
			if ( !strcmp(tipoOrdem, "aleat") )
				opcao = 3;
		}
	}

	switch (opcao){ //pode ser 1-normal 2-invertida 3-aleatoria
	case 1:
		criaArquivoOrdemNormal(numeroInicial, numeroFinal, argv[4]);
		break;
	case 2:
		criaArquivoOrdemInvertida(numeroInicial, numeroFinal, argv[4]);
		break;
	case 3:
		criaArquivoOrdemAleatoria(numeroInicial, numeroFinal, argv[4]);
		break;
	}
	return 0;
}*/
